using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
using Xivo.Shared;

namespace Xivo
{
  public partial class ChannelListControl : UserControl, Shared.IXivoPlugin
  {
    public delegate void StringEvent(ChannelListControl sender, string e);
    public event StringEvent onHotListAdd;

    SortedList<int, Shared.ChannelInfo> currentChannelList;
    int channelRowHeight;

    int ListTop = 0;
    int ListBottom = 255;
    int HighlightedChannel = -1;
    int SelectedChannel;

    Brush bText = System.Drawing.Brushes.Black;
    Brush bTextHighlighted = System.Drawing.Brushes.White;
    Brush bHighlighted = System.Drawing.Brushes.DarkGray;
    Brush bSelected = System.Drawing.Brushes.Red;
    Brush bCurrentChannel = System.Drawing.Brushes.DarkBlue;
    Font font = new Font("Arial", 10);

    private Shared.RadioBase PCR;
    void Shared.IXivoPlugin.Init()
    {
      this.PCR = Shared.Common.Radio;
      PCR.onPowerChange += new Delegates.IntEvent(PCR_onPowerChange);
      PCR.onChannelChange += new Delegates.IntEvent(PCR_onChannelChange);
      PCR.onChannelInfoReceived += new Delegates.InfoEvent(PCR_onChannelInfoReceived);
    }

    void PCR_onChannelInfoReceived(ChannelInfo info) {
      if (InvokeRequired)
        Invoke(new Xivo.Shared.Delegates.InfoEvent(PCR_onChannelInfoReceived), new object[] { info });
      else {
        lRefreshing.Text = info.channelStr;
        pbChannelList.Refresh();
      }
    }

    void PCR_onChannelChange(int value) {
      if (InvokeRequired)
        Invoke(new Xivo.Shared.Delegates.IntEvent(PCR_onChannelChange), new object[] { value });
      else {
        SelectedChannel = -1;
        pbChannelList.Refresh();
      }
    }

    void PCR_onPowerChange(int value) {
      if (InvokeRequired)
        Invoke(new Xivo.Shared.Delegates.IntEvent(PCR_onPowerChange), new object[] { value });
      else {
        if (value == 0)
          TimerEnabled = false;
        else
          TimerEnabled = true;
      }
    }

    void Shared.IXivoPlugin.Start()
    {
      setChannelListMode(channelListModeEnum.favorites);
      setChannelTop(PCR.CurrentChannel - 5);
    }

    void Shared.IXivoPlugin.ShutDown()
    {
      TimerEnabled = false;
    }

    private bool TimerEnabled
    {
      get { return Timer1.Enabled; }
      set { Timer1.Enabled = value; }
    }

    public enum channelListModeEnum
    {
      allChannels,
      favorites
    }
    channelListModeEnum channelListMode;

    public ChannelListControl()
    {
      InitializeComponent();
    }

    private void pbChannelList_MouseMove(object sender, MouseEventArgs e)
    {
      byte selected = (byte)(e.Y / channelRowHeight + ListTop - 1);
      if (selected < currentChannelList.Count)
      {
        HighlightedChannel = currentChannelList.Values[selected].channel;
        //SelectedChannel = -1;
        pbChannelList.Refresh();
      }
    }

    public void setChannelListMode(channelListModeEnum mode)
    {
      channelListMode = mode;
      bAllChannels.BackColor = System.Drawing.Color.Transparent;
      bFavorites.BackColor = System.Drawing.Color.Transparent;
      switch (mode)
      {
        case channelListModeEnum.allChannels:
          bAllChannels.BackColor = System.Drawing.Color.Red;
          currentChannelList = PCR.channels.AllChannels;
          break;
        case channelListModeEnum.favorites:
          currentChannelList = PCR.channels.Favorites;
          bFavorites.BackColor = System.Drawing.Color.Red;
          break;
      }
      showCurrentChannel();
      pbChannelList.Refresh();
    }

    private void addToFavoritesToolStripMenuItem_Click(object sender, EventArgs e)
    {
      Shared.ChannelInfo info = PCR.channels.AllChannels[SelectedChannel];
      if (!PCR.channels.Favorites.ContainsKey(info.channel))
        PCR.channels.Favorites.Add(info.channel, info);
    }

    void setChannelTop(int newValue)
    {
      vsChannelList.Value = Common.bounds(vsChannelList.Minimum, vsChannelList.Maximum, newValue);
      ListTop = vsChannelList.Value;
    }

    public void ChannelListControl_MouseWheel(object sender, MouseEventArgs e)
    {
      if (e.Delta > 0)
        setChannelTop(ListTop - 5);
      else if (e.Delta < 0)
        setChannelTop(ListTop + 5);
    }

    private void ChannelListControl_Load(object sender, EventArgs e)
    {
      channelRowHeight = font.Height;
    }

    private void bAllChannels_Click(object sender, EventArgs e)
    {
      setChannelListMode(channelListModeEnum.allChannels);
    }

    private void bFavorites_Click(object sender, EventArgs e)
    {
      setChannelListMode(channelListModeEnum.favorites);
    }

    private void lRefreshing_Click(object sender, EventArgs e)
    {
      refreshVisible();
    }

    private void Timer1_Tick(object sender, EventArgs e)
    {
      if (this.ParentForm != null
        && this.ParentForm.WindowState != FormWindowState.Minimized
        && this.Visible)
        refreshVisible();
    }

    void refreshVisible()
    {
      if (!PCR.Busy)
      {
        lRefreshing.Text = "vis";
        for (int i = ListTop; i < ListBottom; ++i)
          PCR.EnqueueChannelInfoRequest(currentChannelList.Values[i]);
        PCR.ServiceChannelInfoQueue();
      }
    }

    void showCurrentChannel()
    {
      if (currentChannelList != null && PCR != null)
      {
        if (currentChannelList.ContainsKey(PCR.CurrentChannel))
        {
          int i = currentChannelList.IndexOfKey(PCR.CurrentChannel);
          if (i < ListTop || i > ListBottom)
            setChannelTop(i - 5);
        }
        else
          setChannelTop(0);
      }
    }

    public void UpdateChannelInfo(ChannelInfo NewInfo)
    {
      if (NewInfo != null)
      {
        lRefreshing.Text = NewInfo.channelStr;
        pbChannelList.Refresh();
      }
    }

    private void addArtistToHotlistToolStripMenuItem_Click(object sender, EventArgs e)
    {
      ChannelInfo info = currentChannelList[SelectedChannel];
      if (onHotListAdd != null)
        onHotListAdd(this, info.longArtist);
      SelectedChannel = -1;
    }

    private void addTiToolStripMenuItem_Click(object sender, EventArgs e)
    {
      ChannelInfo info = currentChannelList[SelectedChannel];
      if (onHotListAdd != null)
        onHotListAdd(this, info.longTitle);
      SelectedChannel = -1;
    }

    public bool isFavorite(int ChannelNumber)
    {
      return PCR.channels.Favorites.ContainsKey(ChannelNumber);
    }

    public void ChangeChannel()
    {

    }

    public void ChannelUp()
    {
      int index = currentChannelList.IndexOfKey(PCR.CurrentChannel);
      index--;
      if (index < 0) index = currentChannelList.IndexOfKey(currentChannelList.Count - 1);
      if (index >= 0 && index < currentChannelList.Count)
        PCR.CurrentChannel = currentChannelList.Values[index].channel;
    }

    public void ChannelDown()
    {
      int index = currentChannelList.IndexOfKey(PCR.CurrentChannel);
      index++;
      if (index >= currentChannelList.Count) index = 0;
      if (index >= 0 && index < currentChannelList.Count)
        PCR.CurrentChannel = (currentChannelList.Values[index].channel) ;
    }

    int[] cols = new int[] { 40, 125, 125, 150 };
    private void pbChannelList_Paint(object sender, PaintEventArgs e)
    {
      drawChannels(e.Graphics, currentChannelList);
    }

    void drawChannels(Graphics g, SortedList<int, Shared.ChannelInfo> list)
    {
      int y = 0;
      int x = 0;
      int col = 0;
      Shared.ChannelInfo info = null;

      g.DrawString("Ch", font, bText, x, y);
      x += cols[col++];
      g.DrawString("Station", font, bText, x, y);
      x += cols[col++];
      g.DrawString("Genre", font, bText, x, y);
      x += cols[col++];
      g.DrawString("Artist", font, bText, x, y);
      x += cols[col++];
      g.DrawString("Title", font, bText, x, y);
      y += font.Height;

      x = 0; col = 0;
      for (int c = 0; c < cols.Length; ++c)
      {
        x += cols[col++];
        g.FillRectangle(bHighlighted, x, y, 1, pbChannelList.Height);
      }
      g.FillRectangle(bText, 0, y, pbChannelList.Width, 1);
      y += 2;

      if (!DesignMode)
      {
        int i = Common.bounds(0,
          Common.bounds(0, int.MaxValue, list.Count - 1),
          ListTop);

        while (y < pbChannelList.ClientSize.Height && i < list.Count)
        {
          info = list.Values[i];
          Brush b = bText;
          if (info.channel == PCR.CurrentChannel)
          {
            g.FillRectangle(bCurrentChannel, 0, y, pbChannelList.Width, channelRowHeight);
            b = bTextHighlighted;
          }
          else if (info.channel == SelectedChannel)
            g.FillRectangle(bSelected, 0, y, pbChannelList.Width, channelRowHeight);
          else if (info.channel == HighlightedChannel)
            g.FillRectangle(bHighlighted, 0, y, pbChannelList.Width, channelRowHeight);

          x = 0; col = 0;
          g.DrawString(info.channelStr, font, b,
            new RectangleF(0, y, 35, font.Height), new StringFormat(StringFormatFlags.DirectionRightToLeft));
          x += cols[col++];
          g.DrawString(info.station, font, b, x, y);
          x += cols[col++];
          g.DrawString(info.genre, font, b, x, y);
          x += cols[col++];
          g.DrawString(info.shortArtist, font, b, x, y);
          x += cols[col++];
          g.DrawString(info.shortTitle, font, b, x, y);
          y += channelRowHeight;
          ++i;
        }
        ListBottom = i;

        vsChannelList.Maximum = currentChannelList.Count;
        vsChannelList.LargeChange = pbChannelList.ClientSize.Height / channelRowHeight - 1;
      }
    }

    private void pbChannelList_MouseUp(object sender, MouseEventArgs e)
    {
      switch (e.Button)
      {
        case MouseButtons.Left:
          SelectedChannel = HighlightedChannel;
          pbChannelList.Refresh();
          PCR.CurrentChannel = (SelectedChannel);
          //byte selected = (byte)(e.Y / channelRowHeight + ListTop - 1);
          //if (selected < currentChannelList.Count)
          //{
          //  PCR.ChangeChannel(currentChannelList.Values[selected].channel);
          //  pbChannelList.Refresh();
          //}
          break;
        case MouseButtons.Right:
          SelectedChannel = HighlightedChannel;
          channelMenu.Show(pbChannelList.PointToScreen(e.Location));
          break;
      }
    }

    private void vsChannelList_ValueChanged(object sender, EventArgs e)
    {
      ListTop = vsChannelList.Value;
      pbChannelList.Refresh();
    }

    public void Cleanup()
    {
      PCR.onChannelChange -= PCR_onChannelChange;
      PCR.onChannelInfoReceived -= PCR_onChannelInfoReceived;
      PCR.onPowerChange -= PCR_onPowerChange;
    }

    private void pbChannelList_MouseLeave(object sender, EventArgs e)
    {
      HighlightedChannel = -1;
      pbChannelList.Refresh();
    }

    private void removeFromFavoritesToolStripMenuItem_Click(object sender, EventArgs e)
    {
      Shared.ChannelInfo info = PCR.channels.AllChannels[SelectedChannel];
      if (PCR.channels.Favorites.ContainsKey(info.channel))
        PCR.channels.Favorites.Remove(info.channel);
      pbChannelList.Refresh();
      SelectedChannel = -1;
    }

    private void bRefresh_Click(object sender, EventArgs e)
    {
      PCR.requestAllChannelInfo();
    }

  }
}
